package com.gitee.hifong45;

import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;

import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.misc.NetscapeCertType;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.cert.CertIOException;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.X509KeyUsage;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.util.encoders.Base64;

import cn.hutool.core.lang.Console;
import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.SmUtil;
import lombok.var;

public class FSM2 {
	public static void main(String[] args) throws Exception {
		var sm2 = SmUtil.sm2();
		KeyPair keyPair = new KeyPair(sm2.getPublicKey(), sm2.getPrivateKey());
		var cert = genSM2X509Certificate(keyPair);
//		saveCertFile(cert, Paths.get("sm2_df.cer"));
//		Console.log(cert.toString());
		
		// 证书内容转 Base64
		var certBs64 = Base64.toBase64String(cert.getEncoded());
		Console.log("certbs64 len={}, text= {}", certBs64.length(), certBs64);
		
//		var certHex = HexUtil.encodeHexStr(cert.getEncoded());
		
		var certHex = genX509CertHex(keyPair);
		Console.log("hexStr len={}, text= {}", certHex.length(), certHex );

	}

	static public X509Certificate fromString(String cert) {
		try {
			var	certificateFactory = CertificateFactory.getInstance("X.509");
//			final String strCertificate = "-----BEGIN CERTIFICATE-----\n" + cert + "\n-----END CERTIFICATE-----\n";
			final java.io.ByteArrayInputStream streamCertificate = new java.io.ByteArrayInputStream(
					cert.getBytes("UTF-8"));
			return (java.security.cert.X509Certificate) certificateFactory.generateCertificate(streamCertificate);
		} catch (Exception ex) {

			System.out.println(ex.getMessage());
		}
		return null;
	}

	public static String genX509CertHex(KeyPair keyPair) throws OperatorCreationException, CertIOException, CertificateException {
		return genX509CertHex(keyPair.getPublic(), keyPair.getPrivate());
	}
	
	public static String genX509CertHex(PublicKey publicKey, PrivateKey privateKey)
			throws OperatorCreationException, CertIOException, CertificateException {
		return HexUtil.encodeHexStr(genSM2X509Certificate(publicKey, privateKey).getEncoded());
	}

	/**
	 * 
	 * @param keyPair 密钥对
	 * @return X509格式证书
	 * @throws Exception 操作异常
	 */
	public static X509Certificate genSM2X509Certificate(KeyPair keyPair) throws Exception {
		return genSM2X509Certificate(keyPair.getPublic(), keyPair.getPrivate());
	}

	public static X509Certificate genSM2X509Certificate(PublicKey publicKey, PrivateKey privateKey) throws CertIOException, OperatorCreationException, CertificateException {
		// 证书签名实现类 附加了 SM3WITHSM2 和 PrivateKey
		JcaContentSignerBuilder jcaContentSB = new JcaContentSignerBuilder("SM3withSM2");
		jcaContentSB.setProvider(new BouncyCastleProvider());
		ContentSigner sigGen = jcaContentSB.build(privateKey);

		// 准备证书信息
		BigInteger sn = BigInteger.valueOf(System.currentTimeMillis());
		// 发行人
		X500Name issuer = new X500NameBuilder(BCStyle.INSTANCE).addRDN(BCStyle.C, "CN").addRDN(BCStyle.O, "JSXYJA")
				.addRDN(BCStyle.ST, "Jiangsu").addRDN(BCStyle.L, "Nanjing").addRDN(BCStyle.CN, "江苏信源久安信息科技有限公司") // 身份
				.build();
		// 使用者
		X500Name subject = new X500NameBuilder(BCStyle.INSTANCE).addRDN(BCStyle.C, "CN").addRDN(BCStyle.O, "personal")
//				.addRDN(BCStyle.ST, "Jiangsu")
//				.addRDN(BCStyle.L, "Nanjing")
				.addRDN(BCStyle.CN, "测试员") // 身份
				.build();
		Date notBefore = new Date();
		Date notAfter = new Date(System.currentTimeMillis() + 14 * 24 * 3600 * 1000);

		// 构造证书信息
		JcaX509v3CertificateBuilder jcaX509v3Cert = new JcaX509v3CertificateBuilder(issuer, sn, notBefore, notAfter,
				subject, publicKey);
		jcaX509v3Cert.addExtension(Extension.keyUsage, false,
				new X509KeyUsage(X509KeyUsage.digitalSignature | X509KeyUsage.nonRepudiation));
		jcaX509v3Cert.addExtension(Extension.extendedKeyUsage, false, extendedKeyUsage());
		jcaX509v3Cert.addExtension(MiscObjectIdentifiers.netscapeCertType, false,
				new NetscapeCertType(NetscapeCertType.sslClient));

		// 构造X.509 第3版的证书构建者
		X509v3CertificateBuilder x509v3Cert = jcaX509v3Cert;

		// 将证书构造参数装换为X.509证书对象
		X509Certificate certificate = new JcaX509CertificateConverter().setProvider(new BouncyCastleProvider())
				.getCertificate(x509v3Cert.build(sigGen));

		return certificate;
	}

	/**
	 * 构造 主题名称
	 * 
	 * @param cn cn项
	 * @return 名称
	 */
	public static X500Name createX500Name(String cn) {
		return new X500NameBuilder(BCStyle.INSTANCE).addRDN(BCStyle.C, "CN").addRDN(BCStyle.O, "JSXYJA")
				.addRDN(BCStyle.ST, "Jiangsu").addRDN(BCStyle.L, "Nanjing").addRDN(BCStyle.CN, cn) // 身份
				.build();
	}

	/**
	 * 获取扩展密钥用途
	 *
	 * @return 增强密钥用法ASN.1对象
	 * @author Cliven
	 */
	public static DERSequence extendedKeyUsage() {
		// // 客户端身份认证
		// ASN1ObjectIdentifier clientAuth = new
		// ASN1ObjectIdentifier("1.3.6.1.5.5.7.3.2");
		// // 安全电子邮件
		// ASN1ObjectIdentifier emailProtection = new
		// ASN1ObjectIdentifier("1.3.6.1.5.5.7.3.4");
		// 构造容器对象
		ASN1EncodableVector vector = new ASN1EncodableVector();
		// 客户端身份认证
		vector.add(KeyPurposeId.id_kp_clientAuth);
		// 安全电子邮件
		vector.add(KeyPurposeId.id_kp_emailProtection);
		return new DERSequence(vector);
	}

	/**
	 * 将证书内容保存到文件
	 * @param x509Certificate X.509格式证书
	 * @param savePath        证书保存路径
	 * @throws CertificateEncodingException 证书编码异常
	 * @throws IOException IO异常
	 */
	public static void saveCertFile(X509Certificate x509Certificate, Path savePath)
			throws CertificateEncodingException, IOException {
		if (Files.exists(savePath)) {
			// 删除已存在文件
			Files.deleteIfExists(savePath);
		}
		// 创建文件
		Files.createFile(savePath);

		// 获取ASN.1编码的证书字节码
		byte[] asn1BinCert = x509Certificate.getEncoded();
		// 编码为BASE64 便于传输
		byte[] base64EncodedCert = Base64.encode(asn1BinCert);
		// 写入文件
		Files.write(savePath, base64EncodedCert);
	}
}
